package com.ncmmall.mall.controller.business.marketing.seckill;

import cn.hutool.core.util.StrUtil;
import com.ncmmall.application.business.marketing.SeckillApplication;
import com.ncmmall.application.securitys.logs.OperationLogApplication;
import com.feijin.commons.exceptions.IllegalRequestException;
import com.feijin.commons.webs.Webs;
import com.ncmmall.domain.business.goods.Goods;
import com.ncmmall.domain.business.goods.QGoods;
import com.ncmmall.domain.business.goods.channel.GoodsChannel;
import com.ncmmall.domain.business.goods.channel.QGoodsChannel;
import com.ncmmall.domain.business.goods.sku.GoodsSku;
import com.ncmmall.domain.business.goods.sku.QGoodsSku;
import com.ncmmall.domain.business.marketing.seckill.QSeckillActivity;
import com.ncmmall.domain.business.marketing.seckill.QSeckillSession;
import com.ncmmall.domain.business.marketing.seckill.SeckillActivity;
import com.ncmmall.domain.business.marketing.seckill.SeckillGoods;
import com.ncmmall.domain.business.marketing.seckill.SeckillSession;
import com.ncmmall.mall.controller.securitys.shiro.Securitys;
import com.ncmmall.mall.params.PageParams;
import com.ncmmall.querychannel.QueryPage;
import com.ncmmall.querychannel.QueryPageRequest;
import com.ncmmall.querychannel.service.QueryChannelService;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 秒杀活动
 *
 * @author linxs
 * @date 2020-02-03 14:35
 */
@Slf4j
@Controller
@RequestMapping(value = "/merchant/seckill")
public class SeckillController {

    @Autowired
    private QueryChannelService queryChannelService;

    @Autowired
    private SeckillApplication seckillApplication;

    @Autowired
    private OperationLogApplication logApplication;

    /**
     * 商品列表
     */
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    private String list(Model model, QueryPageRequest pageRequest, SeckillActivity seckill) {

        Map<String, Object> params = new HashMap<>();
        params.put("id", Securitys.currentUser().getId());

        String hql = builderSQL("select u from SeckillActivity u where u.merchant.id = :id ", params, seckill);
        QueryPage<SeckillActivity> page = queryChannelService.findPage(hql, pageRequest.setParams(params), SeckillActivity.class);

        model.addAttribute("page", page).addAttribute("params", seckill);

        return "merchant/marketing/seckill/list";
    }


    /**
     * 详情
     */
    @RequestMapping(value = "/{id}/detail", method = RequestMethod.GET)
    private String detail(Model model, @PathVariable("id") long id) {

        SeckillActivity seckillActivity = queryChannelService.findOne(QSeckillActivity.seckillActivity.id.eq(id), SeckillActivity.class);

        List<SeckillGoods> goodses = queryChannelService.findAll("select s from SeckillGoods s where s.seckillActivity.id = :id ", ImmutableMap.of("id", seckillActivity.getId()), SeckillGoods.class);

        for (SeckillGoods goodse : goodses) {
            List<GoodsSku> skus = queryChannelService.findAll(QGoodsSku.goodsSku.goods.eq(goodse.getGoods()), GoodsSku.class);
            goodse.getGoods().setSkus(skus);
        }

        List<SeckillSession> seckillSessions = queryChannelService.findAll("select s from SeckillSession s where s.status = 2 and s.isValidity = 1 and s.applyDeadline > :now", ImmutableMap.of("now", now()), SeckillSession.class);
        model.addAttribute("seckill", seckillActivity).addAttribute("seckillSessions", seckillSessions).addAttribute("seckillGoodses", goodses).addAttribute("_method", "PUT");

        return "merchant/marketing/seckill/detail";

    }

    private String now() {
        return DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
    }


    /**
     * 添加秒杀活动页面
     */
    @RequestMapping(value = "/create", method = RequestMethod.GET)
    private String create(Model model) {

        SeckillActivity seckillActivity = new SeckillActivity();
        List<SeckillSession> seckillSessions = queryChannelService.findAll("select s from SeckillSession s where s.merchantScopeType = 1 and s.status = 2 and s.isValidity = 1 and s.applyDeadline >= :now ", ImmutableMap.of("now", now()), SeckillSession.class);
        List<SeckillSession> scopes = queryChannelService.findAll("select s.seckillSession from SeckillSessionMerchantScope s where s.merchant.id = :id and s.seckillSession.status = 2 and s.seckillSession.isValidity = 1 and s.seckillSession.applyDeadline >= :now ", ImmutableMap.of("id", Securitys.currentUser().getId(), "now", now()), SeckillSession.class);
        if (!scopes.isEmpty()) {
            seckillSessions.addAll(scopes);
        }

        model.addAttribute("seckill", seckillActivity).addAttribute("seckillSessions", seckillSessions).addAttribute("_method", "POST");

        return "merchant/marketing/seckill/form";

    }

    /**
     * 添加秒杀活动
     */
    @RequestMapping(value = "/create", method = RequestMethod.POST)
    @ResponseBody
    private Map<String, Object> create(@RequestHeader("X-Requested-With") String requestWith, SeckillActivity seckillActivity) {

        try {
            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }
            seckillActivity.setMerchant(Securitys.currentUser());
            seckillApplication.createSeckillActivity(seckillActivity);
            return ImmutableMap.of("status", true);

        } catch (Exception e) {
            log.error("[添加秒杀活动异常]", e);
            return ImmutableMap.of("status", false);
        }
    }

    /**
     * 删除
     */
    @RequestMapping(value = "/remove", method = RequestMethod.DELETE)
    @ResponseBody
    private Map<String, Object> remove(@RequestHeader("X-Requested-With") String requestWith, SeckillActivity seckillActivity) {

        try {
            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }
            seckillApplication.removeSeckillActivity(seckillActivity);
            return ImmutableMap.of("status", true);
        } catch (Exception e) {
            log.error("[添加秒杀活动异常]", e);
            return ImmutableMap.of("status", false);
        }
    }

    /**
     * 编辑
     */
    @RequestMapping(value = "/{id}/modify", method = RequestMethod.GET)
    private String modify(Model model, @PathVariable("id") long id) {

        SeckillActivity seckillActivity = queryChannelService.findOne(QSeckillActivity.seckillActivity.id.eq(id), SeckillActivity.class);

        List<SeckillGoods> goodses = queryChannelService.findAll("select s from SeckillGoods s where s.seckillActivity.id = :id ", ImmutableMap.of("id", seckillActivity.getId()), SeckillGoods.class);

        for (SeckillGoods goodse : goodses) {
            List<GoodsSku> skus = queryChannelService.findAll(QGoodsSku.goodsSku.goods.eq(goodse.getGoods()), GoodsSku.class);
            goodse.getGoods().setSkus(skus);
        }

        List<SeckillSession> seckillSessions = queryChannelService.findAll("select s from SeckillSession s where s.status = 2 and s.isValidity = 1 and s.applyDeadline >= :now", ImmutableMap.of("now", now()), SeckillSession.class);
        model.addAttribute("seckill", seckillActivity).addAttribute("seckillSessions", seckillSessions).addAttribute("seckillGoodses", goodses).addAttribute("_method", "PUT");

        return "merchant/marketing/seckill/form";

    }

    /**
     * 编辑
     */
    @RequestMapping(value = "/{id}/modify", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> modify(@RequestHeader("X-Requested-With") String requestWith, SeckillActivity seckillActivity) {

        try {

            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            seckillActivity.setMerchant(Securitys.currentUser());
            seckillApplication.modifySeckillActivity(seckillActivity);

            return ImmutableMap.of("status", true);

        } catch (Exception e) {
            log.error("[编辑秒杀活动异常]", e);
            return ImmutableMap.of("status", false);
        }
    }

    /**
     * 查询秒杀场次信息
     */
    @RequestMapping(value = "/querySession", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> querySession(@RequestParam("id") long id) {
        SeckillSession seckillSession = queryChannelService.findOne(QSeckillSession.seckillSession.id.eq(id), SeckillSession.class);
        return ImmutableMap.of("status", true, "seckillSession", seckillSession);
    }


    /**
     * 提交审核
     */
    @RequestMapping(value = "/applyProcess", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> applyProcess(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, @RequestParam("id") long id) {
        try {

            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            SeckillActivity seckillActivity = queryChannelService.findOne(QSeckillActivity.seckillActivity.id.eq(id), SeckillActivity.class);
            seckillApplication.applyProcessSeckillActivity(seckillActivity);
            logApplication.eventOfMerchant(Securitys.currentUser(), "提交秒杀商品审核", Securitys.getIp(request));
            return ImmutableMap.of("status", true);
        } catch (Exception e) {
            log.error("[提交秒杀商品审核异常]", e);
            return ImmutableMap.of("status", false);
        }
    }

    /**
     * 下架
     */
    @RequestMapping(value = "/soldout", method = RequestMethod.PUT)
    @ResponseBody
    private Map<String, Object> soldout(HttpServletRequest request, @RequestHeader("X-Requested-With") String requestWith, @RequestParam("id") long id) {
        try {

            if (!Webs.isAjaxRequest(requestWith)) {
                throw new IllegalRequestException("request must be Ajax!");
            }

            SeckillActivity seckillActivity = queryChannelService.findOne(QSeckillActivity.seckillActivity.id.eq(id), SeckillActivity.class);

            seckillApplication.soldoutSeckillActivity(seckillActivity);
            logApplication.eventOfMerchant(Securitys.currentUser(), "下架秒杀活动", Securitys.getIp(request));

            return ImmutableMap.of("status", true);

        } catch (Exception e) {
            log.error("[下架秒杀商品异常]", e);
            return ImmutableMap.of("status", false);
        }
    }

    /**
     * 选择商品设置为秒杀
     */
    @RequestMapping(value = "/chooseGoods", method = RequestMethod.GET)
    private String chooseGoods(Model model, PageParams pageParams, Goods coupon, String ids) {

        QueryPageRequest pageRequest = new QueryPageRequest().setPageNo(pageParams.getPageNo());
        Map<String, Object> params = Maps.newHashMap();
        params.put("id", Securitys.currentUser().getId());
        String hql = builderGoodsSQL("select u from Goods u where u.merchant.id = :id and u.status = 3 and u.marketingType = 0 ", params, coupon, ids);
        QueryPage<Goods> page = queryChannelService.findPage(hql, pageRequest.setParams(params), Goods.class);

        model.addAttribute("page", page)
                .addAttribute("params", coupon)
                .addAttribute("channels", queryChannelService.findAll("select c from GoodsChannel c where c.deleteStatus = 0 and  c.level = 1 and c.status = 1 ", GoodsChannel.class));

        return "merchant/marketing/seckill/chooseGoods";
    }


    @RequestMapping(value = "/queryGoodses", method = RequestMethod.GET)
    @ResponseBody
    private Map<String, Object> queryGoodses(@RequestParam("ids") String ids) {

        List<Long> longIds = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(ids).stream().map(Long::parseLong).collect(Collectors.toList());
        return ImmutableMap.of("status", true, "goodses", queryChannelService.findAll(QGoods.goods.id.in(longIds), Goods.class));

    }

    private String builderGoodsSQL(String sql, Map<String, Object> params, Goods goods, String ids) {

        if (goods.getIsSupplier() > 0) {
            sql += " and u.isSupplier = 1 ";
        } else {
            sql += " and u.isSupplier = 0 ";
        }

        if (null != goods.getGoodsChannel() && goods.getGoodsChannel().getId() > 0) {
            goods.setGoodsChannel(queryChannelService.findOne(QGoodsChannel.goodsChannel.id.eq(goods.getGoodsChannel().getId()), GoodsChannel.class));

            sql += " and u.goodsChannel.id = :cid ";
            params.put("cid", goods.getGoodsChannel().getId());

        } else if (null != goods.getGoodsChannel() && goods.getGoodsChannel().getParent().getId() > 0) {
            goods.getGoodsChannel().setParent(queryChannelService.findOne(QGoodsChannel.goodsChannel.id.eq(goods.getGoodsChannel().getParent().getId()), GoodsChannel.class));

            sql += " and u.goodsChannel.parent.id = :cid ";
            params.put("cid", goods.getGoodsChannel().getParent().getId());

        } else if (null != goods.getGoodsChannel() && goods.getGoodsChannel().getParent().getParent().getId() > 0) {
            goods.getGoodsChannel().getParent().setParent(queryChannelService.findOne(QGoodsChannel.goodsChannel.id.eq(goods.getGoodsChannel().getParent().getParent().getId()), GoodsChannel.class));

            sql += " and u.goodsChannel.parent.parent.id = :cid ";
            params.put("cid", goods.getGoodsChannel().getParent().getParent().getId());
        }

        if (goods.getMerchant() != null && goods.getMerchant().getId() > 0) {
            sql += " and u.merchant.id = :merchantId ";
            params.put("merchantId", goods.getMerchant().getId());
        }

        if (goods.getStatus() > 0) {
            sql += " and u.status = :status ";
            params.put("status", goods.getStatus());
        } else {
            sql += " and u.status in (3,6) ";
        }

        if (!Strings.isNullOrEmpty(goods.getGoodsNo())) {
            sql += " and u.goodsNo like :goodsno ";
            params.put("goodsno", "%" + goods.getGoodsNo() + "%");
        }

        if (!Strings.isNullOrEmpty(goods.getName())) {
            sql += " and u.name like :name ";
            params.put("name", "%" + goods.getName() + "%");
        }

        if (StringUtils.isNotBlank(ids)) {
            sql += " and u.id not in :ids ";
            params.put("ids", StrUtil.splitTrim(ids, '-').stream().map(Long::valueOf).collect(Collectors.toList()));
        }


        if (!Strings.isNullOrEmpty(goods.getOrderByCreateTime())) {
            sql += " order by u.createTime " + goods.getOrderByCreateTime();
        } else if (!Strings.isNullOrEmpty(goods.getOrderByPrice())) {
            sql += " order by u.defaultPrice " + goods.getOrderByPrice();
        } else if (!Strings.isNullOrEmpty(goods.getOrderByStore())) {
            sql += " order by u.store " + goods.getOrderByStore();
        } else if (!Strings.isNullOrEmpty(goods.getOrderBySalesVolume())) {
            sql += " order by u.salesVolume " + goods.getOrderBySalesVolume();
        } else {
            sql += " order by u.createTime desc ";
        }

        return sql;
    }


    /**
     * 条件筛选
     */
    private String builderSQL(String sql, Map<String, Object> params, SeckillActivity seckillActivity) {

        if (seckillActivity.getSeckillSession() != null && StrUtil.isNotBlank(seckillActivity.getSeckillSession().getName())) {
            sql += " and u.seckillSession.name like :name ";
            params.put("name", "%" + seckillActivity.getSeckillSession().getName() + "%");
        }

        if (seckillActivity.getStatus() > 0) {
            sql += " and u.status = :status ";
            params.put("status", seckillActivity.getStatus());
        }

        sql += " order by u.createTime desc ";

        return sql;
    }


}
